package marionito.domaine;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.MapKeyColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

import marionito.usecasesimpl.GestionPartiesImpl;
import marionito.util.Util;

import com.sun.istack.internal.NotNull;

@Entity
@Table(name = "PARTIES", schema = "MARIONITO")
@SuppressWarnings("serial")
public class Partie implements Serializable {
	public static final int MAX_JOUEURS = 3;
	public static final int MIN_JOUEURS = 2;
	public static final int TEMPS_DEBUT_PARTIE = 15;
	public static final int TEMPS_INACTIVE = 15;

	public enum Etat {
		PAS_COMMENCEE {
			boolean ajouterJoueurPartie(JoueurPartie joueurPartie, Partie partie) {
				partie.joueursPartie.add(joueurPartie);
				return true;
			}

			List<Jeton> commencerPartie(Partie partie) {
				partie.etat = Etat.COMMENCEE;
				List<Jeton> jetonsTires = new ArrayList<Jeton>(3);
				for (int i = 0; i < 3; i++) {
					jetonsTires.add(partie.mapJetons
							.get(partie.indiceJetonCourant++));
				}

				return jetonsTires;
			}

		},
		COMMENCEE {
			int lancerDe(Partie partie) {
				partie.resultatDe = (int) ((Math.random() * 19) + 1);
				return partie.resultatDe;
			}

			Jeton jetonSuivant(Partie partie) {
				if (partie.indiceJetonCourant == 12)
					return null;
				return partie.mapJetons.get(partie.indiceJetonCourant++);
			}

		},

		TERMINEE {
			List<JoueurPartie> scoresTriesPartie(Partie partie) {
				List<JoueurPartie> joueursPartie = partie.joueursPartie;
				List<JoueurPartie> scores = new ArrayList<JoueurPartie>();
				for (JoueurPartie jp : joueursPartie) {
					jp.calculerScore();
					scores.add(jp);
				}
				Collections.sort(scores, new Comparator<JoueurPartie>() {

					@Override
					public int compare(JoueurPartie o1, JoueurPartie o2) {
						return o1.getScore() - o2.getScore();
					}
				});

				return scores;
			}
		};

		boolean ajouterJoueurPartie(JoueurPartie joueurPartie, Partie partie) {
			return false;
		}

		int lancerDe(Partie partie) {
			return -1;
		}

		List<Jeton> commencerPartie(Partie partie) {
			return null;
		}

		Jeton jetonSuivant(Partie partie) {
			return null;
		}

		List<Joueur> vainqueurs(Partie partie) {
			List<Joueur> vainqueurs = null;

			for (JoueurPartie jp : partie.getJoueursPartie()) {
				if (jp.getScore() == 12) {
					if (vainqueurs == null) {
						partie.etat = Etat.TERMINEE;
						vainqueurs = new ArrayList<Joueur>();
					}

					vainqueurs.add(jp.getJoueur());
				}
			}
			return vainqueurs;
		}

		List<JoueurPartie> scoresTriesPartie(Partie partie) {
			return null;
		}

	}

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	@NotNull
	@Enumerated(EnumType.STRING)
	private Etat etat;

	@Column(name = "indice_Jeton_Courant", nullable = false)
	private int indiceJetonCourant;

	@NotNull
	private String nom;

	@Column(name = "resultat_de", nullable = false)
	private int resultatDe;

	@ManyToMany
	@JoinTable(schema = "MARIONITO", name = "JETONS_PARTIES", joinColumns = { @JoinColumn(name = "PARTIE_ID") }, inverseJoinColumns = { @JoinColumn(name = "JETON_ID") }, uniqueConstraints = { @UniqueConstraint(columnNames = {
			"PARTIE_ID", "JETON_ID" }) })
	@MapKeyColumn(name = "POSITION")
	private Map<Integer, Jeton> mapJetons = new HashMap<Integer, Jeton>();

	@OneToMany(mappedBy = "partie")
	private List<JoueurPartie> joueursPartie = new ArrayList<JoueurPartie>();

	protected Partie() {
		super();
	}

	public Partie(String nom) {
		Util.checkString(nom);
		this.nom = nom;
		this.indiceJetonCourant = 0;

		List<Jeton> jetonsTries = new ArrayList<Jeton>(
				GestionPartiesImpl.jetons);
		Collections.shuffle(jetonsTries);
		for (int i = 0; i < 12; i++) {
			mapJetons.put(i, jetonsTries.get(i));
		}

		this.etat = Etat.PAS_COMMENCEE;

	}

	public int getId() {
		return id;
	}

	public Etat getEtat() {
		return etat;
	}

	public int getIndiceDernierJetonEnvoye() {
		return indiceJetonCourant;
	}

	public String getNom() {
		return nom;
	}

	public int getResultatDe() {
		return resultatDe;
	}

	public Map<Integer, Jeton> getJetons() {
		return mapJetons;
	}

	public List<JoueurPartie> getJoueursPartie() {
		return joueursPartie;
	}

	public int lancerDe() {
		return etat.lancerDe(this);
	}

	public boolean ajouterJoueurPartie(JoueurPartie joueurPartie) {
		return etat.ajouterJoueurPartie(joueurPartie, this);
	}

	public List<Jeton> commencerPartie() {
		return etat.commencerPartie(this);
	}

	public Jeton jetonSuivant() {
		return etat.jetonSuivant(this);
	}

	public List<Joueur> vainqueurs() {
		return etat.vainqueurs(this);
	}

	public List<JoueurPartie> scoresTriesPartie() {
		return etat.scoresTriesPartie(this);
	}
}
